www.gusucode.com > VC++ RingSDK界面库 > VC++ RingSDK界面库/code/libsrc/ringdib/gif.cpp

    /**********************************************************************
//
//
//        ##########                          ######  #########   # ######    #
//      #############                      ########### ######### #########  ###
//     ######## # ###  ##                 ############# ##    ## #####  # ####
//     ####  ##    ## ###                 ###     ### # #      #####   #####
//          #     ###  #            #     ##       ##  ##      ##     ###
//         ## ###### ##      ##  ####    ####          #       #     ##
//       #########  ###  ## ### #######   ######      ##      ##    ###
//      ######      ##  ######  ##  ##       ####     #      ##     ####
//     #######     ##   ###### ##  ###          ##   ##     ###    ######
//     #########   ##  ###### ## ######         ### ##    ###      #  #####
//    ##    ###### ####### ### #### ##  ## #######  ########      ##    ####
//    ##      #### ###  #  ### ### ##  ##########   ######       ##      ####
//   ##         ##                ##   #########    ####         #         ##
//               #              ###
//                              ##
//                             ###
//                             ##
//
//
//							RingSDK多媒体类库 ringdib.lib
//作者:临风
//
//版本:1.0
//
//声明:本类库可以自由使用而不须对作者作出任何回报,但作者希望能得到
//		  你的鼓励和支持。你可以对类库源码作出修改和改进,但希望你能在
//		  修改的同时给作者一份同样的副本。
//		  本类库不得用于任何商业用途,如确实需要,请与作者联系。
//
//e-mail:ringphone@sina.com
//
//原文件名:gif.cpp
//
//说明:GIF图象载入的实现。
//
**********************************************************************/
#define MAKE_SELF_LIB
#include "ringdib.h"

#pragma pack(push,1)
typedef struct _gifhead{
	char szID[6];		//GIF87a or GIF89a
   WORD wWidth;
   WORD wHeight;
   BYTE bFlag;
   BYTE bgColor;		//背景色
	//char w_mod_h;     //图象纵横尺寸比,=(w_mod_h+15)/64
//w_mod_h程序中未用到,因为字节对齐的问题,结构中加上该字段
//导致数据解码出错,因此去掉该字段,并简单将接下来读取的数据
//指针+1跳过该字段。
}GIFHEADER,*LPGIFHEADER;

typedef struct _localimageinfo{	//图象数据块信息
   WORD wLeft;                   //图象左位置坐标
   WORD wTop;                    //图象上位置坐标
	WORD wWidth;                  //图象宽
   WORD wHeight;                 //图象高
   BYTE bFlag;                   //压缩字段
}LOCALINFO,*LPLOCALINFO;

typedef void(*OUTDATA)();

OUTDATA outdataFunc;					//LZW解码数据输出程序指针,方便更改数据输出程序

LPLOCALINFO lInfo;
LPBYTE m_SBits=NULL;					//单个图象数据

LPBYTE gPal=NULL,lPal=NULL;		//gPal:全局调色板,lPal:局部调色板
LPBYTE lpGifData=NULL,lpDelData; //lpDelData,=最初的lpGifData,lpGifData需要变动,so 析构时Del(lpDelData)

DWORD aniGifThread(RingDIB* rdib);
void DrawLocalPic(RingDIB *rdib,COLORREF* dest,COLORREF* bits,LPANIGIFPIC lpAniGifPic);

////////////////-----以下定义为LZW解码所用---------////////////////////////////
typedef struct tagLZW_DATA
{
	short base;
	BYTE newcode;
	short length;
}LZW_DATA,*LPLZW_DATA;
#pragma pack(pop)

int first_code, curr_bit_size, bit_overflow;
int bit_pos, data_pos, data_len, entire, code;
int clear_code, data_length, cnt, bit_size;
LPLZW_DATA lpstr=NULL;
LPBYTE lpLzw_Data=NULL;
int interlace,trans_index=-1;				//隔行扫描间隔,透明色索引
int curr_scan;		//当前扫描次数
int nLeft,nTop,nWidth,nHeight;

//ringFile x;

void clear_table(void);
void get_code(void);
void get_data(int num);
void output_data(void);					//静态GIF解码数据输出程序
void output_localdata(void);        //动态GIF单个图象解码数据输出程序
void DecodeLZW(void);
void resetVar();		//重置全局变量
////////////////-----LZW解码定义结束---------////////////////////////////

BOOL LoadGIF(LPCTSTR szFilename,RingDIB* lprd,int iFlag,LPSTR lpszFormat)
{
	if(iFlag == DIB_GETFORMAT)
	{
		if(lpszFormat)
		{
			wsprintf(lpszFormat,"gif");
			return TRUE;
		}
		else
			return FALSE;
	}
	
	if(szFilename == NULL || lprd == NULL)
		return FALSE;

	GIFHEADER gifHeader;
	LPANIGIFPIC lpAniGifPic = NULL;
   LPLOCALGIFINFO lpGifInfo = lprd->GetLocalGifInfo();
	if(lpGifInfo == NULL)
		return FALSE;
	
//x="c:\\dibdebug.txt";
//x.Create(RF_NEW);

	ringFile rf(szFilename);
   rf.Open();
	outdataFunc=output_data;

   if(!rf.Read(&gifHeader,sizeof(GIFHEADER)) || gifHeader.szID[0] != 'G' || 
		gifHeader.szID[1] != 'I' || gifHeader.szID[2] != 'F' || 
		gifHeader.szID[3] != '8' || gifHeader.szID[5] != 'a')
      return FALSE;
	else if(iFlag == DIB_QUERYSUPPORT)
		return TRUE;

   if(!lprd->Create(gifHeader.wWidth,gifHeader.wHeight))
   {
     	//Errmsg("内存分配错误,不能创建图象。");
      rf.Close();
	   return FALSE;
   }
	
   nWidth=gifHeader.wWidth;
   nHeight=gifHeader.wHeight;

   DWORD dwFileSize=rf.Size()-sizeof(GIFHEADER);
   lpGifData=(LPBYTE)New(dwFileSize);
   if(lpGifData==NULL)
   {
   	rf.Close();
   	return FALSE;
   }

   if(!rf.Read(lpGifData,dwFileSize))
   {
   	rf.Close();
   	return FALSE;
   }
   rf.Close();
	
	lpDelData=lpGifData;

	lpGifData ++;
//int ps;
   
   if((gifHeader.bFlag&0x80))	//有全局调色板
   {
   	int palsize=1<<((gifHeader.bFlag&0x07)+1);
		palsize=(palsize<<1)+palsize;       //palsize*3
      gPal=(LPBYTE)lpGifData;
      lpGifData+=palsize;
//ps=palsize;
   }

   if(gPal!=NULL)
   {
   	int bg=gifHeader.bgColor*3+2;
   	lprd->Fill(gPal[bg],gPal[bg-1],gPal[bg-2]);
      lpGifInfo->bgC = lprd->Data()[0];
   }

   while((lpGifData-lpDelData)<=(int)dwFileSize)
   {
   	switch(*lpGifData)
      {
         case 0x2C:			//图象描述符
         {
         	lpGifData++;
            lInfo=(LPLOCALINFO)lpGifData;

         	lpGifData+=9;
            if((lInfo->bFlag&0x80))	//有局部调色板
			   {
			   	int lpalsize=1<<((lInfo->bFlag&0x07)+1);
					lpalsize=(lpalsize<<1)+lpalsize;       //palsize*3
			      lPal=(LPBYTE)lpGifData;
			      lpGifData+=lpalsize;
			   }
            else if(gPal!=NULL)
            	lPal=NULL;

            if(lInfo->bFlag&0x40)
            	interlace = 8;
				else
					interlace = 1;

            curr_scan=1;

            m_SBits=(LPBYTE)lprd->Data();

            if(lpAniGifPic)
            {
            	lpAniGifPic->x = lInfo->wLeft;
               lpAniGifPic->y = lInfo->wTop;
               lpAniGifPic->width = lInfo->wWidth;
               lpAniGifPic->height = lInfo->wHeight;
               if(lpAniGifPic->curr!=NULL)			//下一个图象分配出错,lprd->m_aniGifPic始终指向新图象,curr应为NULL
               {
						Del(lpDelData);
		            resetVar();
      		      return TRUE;
               }
               lpAniGifPic->curr = (COLORREF*)New(lInfo->wWidth*lInfo->wHeight*4);
               if(lpAniGifPic->curr == NULL)
               {
						Del(lpDelData);
		            resetVar();
      		      return TRUE;
               }
               m_SBits = (LPBYTE)lpAniGifPic->curr;
               outdataFunc = output_localdata;

               if(lpAniGifPic->keycolor != 0xFFFFFFFF)
               {
                  LPBYTE lpPal;
               	if(lPal!=NULL)
						 	lpPal = lPal;
						else
							lpPal = gPal;

                  if(lpAniGifPic->keycolor == 1)
                     lprd->SetColorKey((lpPal[trans_index]<<16)+(lpPal[trans_index-1]<<8)+lpPal[trans_index-2]);

                  lpAniGifPic->keycolor=(lpPal[trans_index]<<16)+(lpPal[trans_index-1]<<8)+lpPal[trans_index-2];
               }
            }
            DecodeLZW();

				//Del(lpDelData);
            //resetVar();
            //return TRUE;
            break;
			}
         case 0x21:
         {
         	lpGifData++;
            switch(*lpGifData)
            {
               case 0xFF:				//应用程序扩展
               	lpGifData+=13;
                  break;
            	case 0xF9:				//图象控制扩展
               {
                  BYTE docase;
                  BOOL trans;
                  WORD delay;

                  lpGifData+=2;
                  docase=(BYTE)(((*lpGifData)>>2)&0x07);
                  if(docase == 0x3)
						   lpGifInfo->bNeedBak = TRUE;

                  trans=(*lpGifData)&1;
                  lpGifData++;
                  delay=*(WORD*)lpGifData;
                  lpGifData+=2;

                  if(trans)
						   trans_index=(int)*lpGifData*3+2;

                  if(delay==0 && lpAniGifPic == NULL)		//无延时,单个图象
	               {
                     if(trans && gPal != NULL)
                       	lprd->SetColorKey((gPal[trans_index]<<16)+(gPal[trans_index-1]<<8)+gPal[trans_index-2]);
                  }
                  else
                  {
		         		lpAniGifPic = lprd->AddAniGifPic(lpAniGifPic,docase,delay,trans);
							if(lpAniGifPic == NULL)
                  	{
		                 	if(lpAniGifPic == NULL)
                     	{
                      		lpGifData+=2;
                       		break;
                     	}                     	
                     }                     
						}
                  lpGifData+=2;
						break;
               }
               case 0xFE:				//注释块
               	for(int i=0;i<254;i++)
                  {
                     lpGifData++;
                  	if(*lpGifData==0)
                     {
                     	lpGifData++;
                        break;
                     }
                  }
                  break;
            }
            break;
         }
         case 0x3B:						//数据流结束
         {
         	Del(lpDelData);
            resetVar();

            if(lpAniGifPic)
            {
            	//将链表头尾相连
					lpAniGifPic->next = lprd->GetAniGifPic();
					lprd->GetAniGifPic()->prev = lpAniGifPic;
					if(lpGifInfo->AniThread == NULL)
						lpGifInfo->AniThread = new RingThread;
					if(lpGifInfo->AniThread)
						lpGifInfo->AniThread->Start((THREADPROC)aniGifThread,(LONG)lprd);
            }
		      return TRUE;
         }
         default:
         	lpGifData++;
            break;
      }
   }
   Del(lpDelData);
   resetVar();
	return FALSE;
}

/////////////////////----  LZW解码  -------///////////////////////////////
void clear_table(void)
{
	first_code = clear_code + 2;
	curr_bit_size = bit_size + 1;
	bit_overflow = 0;
}

void get_code(void)
{
	if(bit_pos+curr_bit_size>8)
   {
		if(data_pos>=data_len)
      {
      	data_len=*lpGifData;
         lpGifData++;
         data_pos=0;
      }
		entire=(*lpGifData<<8)+entire;
      lpGifData++;
		data_pos ++;
	}
	if(bit_pos+curr_bit_size>16)
   {
		if(data_pos>=data_len)
      {
      	data_len=*lpGifData;
         lpGifData++;
         data_pos=0;
      }
		entire=(*lpGifData<<16)+entire;
      lpGifData++;
		data_pos ++;
	}

	code=(entire>>bit_pos)&((1<<curr_bit_size)-1);

	if(bit_pos+curr_bit_size>8)
		entire>>=8;
	if(bit_pos+curr_bit_size>16)
		entire>>=8;
	bit_pos=(bit_pos+curr_bit_size)%8;
	if(bit_pos==0)
   {
		if(data_pos>=data_len)
      {
      	data_len=*lpGifData;
         lpGifData++;
         data_pos=0;
      }
		entire=*lpGifData;
      lpGifData++;
		data_pos ++;
	}
}

void get_data(int num)
{
	if(num<clear_code)
	{
		data_length = 1;
		lpLzw_Data[0]=lpstr[num].newcode;
	}
	else
	{
		cnt=lpstr[num].length;
		data_length=cnt;
		while(cnt>0)
		{
			cnt--;
			lpLzw_Data[cnt]=lpstr[num].newcode;
			num=lpstr[num].base;
		}
	}
}

void output_data(void)
{
   LPBYTE lpPal;
   int pos;
   int temp;

   if(lPal!=NULL)
	 	lpPal = lPal;
   else
		lpPal = gPal;

   pos=(nLeft+nTop*nWidth)<<2;

//x.Write(lpPal,256*3);

	for(int i=0; i<data_length;i++)
	{
      temp=lpLzw_Data[i]*3+2;
      //if(temp!=trans_index)
      //{
			m_SBits[pos]=lpPal[temp];
   	   pos++;temp--;
      	m_SBits[pos]=lpPal[temp];
	      pos++;temp--;
   	   m_SBits[pos]=lpPal[temp];
      	pos++;
	      m_SBits[pos]=0;
   	   pos++;
      //}
      //else
      	//pos+=4;

		nLeft++;

		if(nLeft>=lInfo->wLeft+lInfo->wWidth)
		{
			nLeft = lInfo->wLeft;
			nTop-=interlace;
         pos=(nLeft+nTop*nWidth)<<2;

			if(nTop<lInfo->wTop)
			{
            switch(interlace)
            {
              	case 8:
                  if(curr_scan==1)
                  {
                    	nTop=lInfo->wTop+nHeight-5;		//-5=-1-4
                     pos=(nLeft+nTop*nWidth)<<2;
                     curr_scan++;
                  }
                  else
                  {
                     interlace=4;
                   	nTop=lInfo->wTop+nHeight-3;		//-3=-1-2
                     pos=(nLeft+nTop*nWidth)<<2;
                  }
						break;
               case 4:
                 	interlace=2;
                 	nTop=lInfo->wTop+nHeight-2;		//-2=-1-1
                  pos=(nLeft+nTop*nWidth)<<2;
                	break;
            }
         }
		}
	}
//x.Close();
}

void output_localdata(void)
{
   LPBYTE lpPal;
   int pos;
   int temp;

   if(lPal!=NULL)
	 	lpPal = lPal;
   else
		lpPal = gPal;

   pos=(nLeft+nTop*lInfo->wWidth)<<2;

	for(int i=0; i<data_length;i++)
	{
      temp=lpLzw_Data[i]*3+2;
		m_SBits[pos]=lpPal[temp];
      pos++;temp--;
      m_SBits[pos]=lpPal[temp];
      pos++;temp--;
      m_SBits[pos]=lpPal[temp];
      pos++;
      m_SBits[pos]=0;
      pos++;

		nLeft++;

		if(nLeft>=lInfo->wWidth)
		{
			nLeft = 0;
			nTop-=interlace;
         pos=(nTop*lInfo->wWidth)<<2;

			if(nTop<0)
			{
            switch(interlace)
            {
              	case 8:
                  if(curr_scan==1)
                  {
                    	nTop=lInfo->wHeight-5;	//-5=-1-4
                     pos=(nTop*lInfo->wWidth)<<2;
                     curr_scan++;
                  }
                  else
                  {
                     interlace=4;
                   	nTop=lInfo->wHeight-3;
                     pos=(nTop*lInfo->wWidth)<<2;
                  }
						break;
               case 4:
                 	interlace=2;
                 	nTop=lInfo->wHeight-2;
                  pos=(nTop*lInfo->wWidth)<<2;
                	break;
            }
         }
		}
	}
}

void DecodeLZW(void)
{
	int old;
   BYTE btData[4096];		//LZW最大码长12BIT,=0xFFF=4095
   LZW_DATA lzw_data[4096];

   lpstr=lzw_data;
   lpLzw_Data=btData;

	bit_size=*lpGifData;
   lpGifData++;
	clear_code=1<<bit_size;

	//初始化解码数据表
   for(short i=0; i<clear_code;i++)
	{
		lzw_data[i].base=-1;
		lzw_data[i].newcode=(unsigned char)i;
		lzw_data[i].length=1;
   }

	bit_pos=0;
	data_len=*lpGifData;
   lpGifData++;
   data_pos=0;
   entire=*lpGifData;
   lpGifData++;
   data_pos ++;
	data_length=0;

   if(outdataFunc==output_data)
   {
	   nLeft=lInfo->wLeft;
   	nTop=lInfo->wTop+nHeight-1;
   }
   else
   {
	   nLeft=0;
   	nTop=lInfo->wHeight-1;
   }

   //解码开始
   clear_table();
	get_code();
   if(code==clear_code)
		get_code();
   get_data(code);
	(*outdataFunc)();
	old = code;

	while(TRUE)
	{
		get_code();

		if(code == clear_code)        //清除码
		{
			clear_table();
			get_code();
			get_data(code);
         (*outdataFunc)();

			old = code;
		}
		else if(code==clear_code+1)	//结束码
      {
      	lpGifData--;
      	break;
      }
      else if(code < first_code)
		{
			get_data(code);
			(*outdataFunc)();

			if(bit_overflow == 0)
         {
				lpstr[first_code].base = (short)old;
				lpstr[first_code].newcode = lpLzw_Data[0];
            lpstr[first_code].length = (short)(lpstr[old].length+1);
            first_code++;
            if(first_code==(1<<curr_bit_size))
            	curr_bit_size ++;
            if(curr_bit_size==13)
            {
					curr_bit_size = 12;
					bit_overflow = 1;
				}
			}

			old = code;
      }
		else
		{
			get_data(old);
			lpLzw_Data[lpstr[old].length]=lpLzw_Data[0];
         data_length++;

         if(bit_overflow==0)
         {
				lpstr[first_code].base=(short)old;
            lpstr[first_code].newcode=lpLzw_Data[0];
            lpstr[first_code].length=(short)(lpstr[old].length+1);
            first_code++;
            if(first_code==(1<<curr_bit_size))
            	curr_bit_size++;
            if(curr_bit_size==13)
            {
					curr_bit_size = 12;
					bit_overflow = 1;
				}
         }
			(*outdataFunc)();
			old = code;
      }
   }
}
//////////////////////--------LZW 解码结束-------------//////////////////////

void resetVar()		//重置全局变量
{
	lInfo=NULL;
	m_SBits=NULL;

	gPal=NULL;
   lPal=NULL;
	lpGifData=NULL;
   lpDelData=NULL;

   trans_index=-1;
   outdataFunc=output_data;

	lpstr=NULL;
	lpLzw_Data=NULL;
}

DWORD aniGifThread(RingDIB* rdib)			//动画GIF显示处理程序(线程)
{
   COLORREF *ani_Bits = NULL;
   RingMSTimer timer;
	LPLOCALGIFINFO lpGifInfo = rdib->GetLocalGifInfo();
	LPANIGIFPIC lpAniGifPic = rdib->GetAniGifPic();
   if(lpGifInfo == NULL)
		return 0;

	if(lpGifInfo->bNeedBak)
   {
   	ani_Bits = (COLORREF*)New(rdib->Width() * rdib->Height() * sizeof(COLORREF));
      if(ani_Bits)
         DrawLocalPic(rdib,ani_Bits,rdib->Data(),lpAniGifPic);
   }

   lpGifInfo->bDibReady = TRUE;

	while(rdib->GetAniGifPic() && lpGifInfo->AniThread && lpGifInfo->AniThread->IsRunning())
   {
      if(lpGifInfo->bActive && lpGifInfo->bDibReady)
	   {
   	   DrawLocalPic(rdib,rdib->Data(),NULL,lpAniGifPic);
         lpGifInfo->funcFilter();
   	      
			if(rdib->GetDestDIB())
			{
				rdib->DrawTo(rdib->GetDestDIB());
				rdib->GetDestDIB()->Draw();
			}
			else
				rdib->Draw();

     		timer.Reset();
	      lpGifInfo->bDibReady = FALSE;
   	}
      else if(timer.PassedTime() >= 10 * lpAniGifPic->delay)
	   {
   	   switch(lpAniGifPic->docase)
      	{
            case 0:                //保持图象,记录为不变图象
            case 1:
              	if(ani_Bits)
	              	DrawLocalPic(rdib,ani_Bits,NULL,lpAniGifPic);
               break;
         	case 2:                //恢复成背景色
           		rdib->FillRect(lpGifInfo->bgC,lpAniGifPic->x,lpAniGifPic->y,lpAniGifPic->width,lpAniGifPic->height);
					break;
   	      case 3:						//恢复前一图象
               if(ani_Bits)
                  DrawLocalPic(rdib,rdib->Data(),ani_Bits,lpAniGifPic);
               break;
      	   default:
              	break;
	      }
   	   if(lpAniGifPic->next)
      	{
          	lpAniGifPic = lpAniGifPic->next;
            lpGifInfo->bDibReady = TRUE;
	         timer.Reset();   	      
      	}
	      timer.Count();
   	}
      Sleep(1);
   }
   Del(ani_Bits);
   return 100;
}

/////////////////////////
//
//将bits图象绘制到dest,bits=NULL,则源图象为动画图象中当前图象
//否则,dest或bits为两相同大小图象,其中之一为记录不变图象(docase=0 or 1)
//
/////////////////////////
void DrawLocalPic(RingDIB *rdib,COLORREF* dest,COLORREF* bits,LPANIGIFPIC lpAniGifPic)
{
	int i,j,y;
   COLORREF *lpmb,*lpl,*lpmbb,*lplb;

   //求剪裁矩形
  	y = lpAniGifPic->y + lpAniGifPic->height;

   lpmb = lpmbb = dest + (rdib->Height() - y) * rdib->Width() + lpAniGifPic->x;

   if(bits == NULL)
   {
      lpl = lplb = lpAniGifPic->curr;

      for(j=0;j<lpAniGifPic->height;j++)
	   {
			for(i=0;i<lpAniGifPic->width;i++)
			{
        		if(lpAniGifPic->keycolor==0xFFFFFFFF || *lpl != lpAniGifPic->keycolor)
					*lpmb = *lpl;
	     		lpmb++;lpl++;
   	   }
			lplb += lpAniGifPic->width;
			lpmbb += rdib->Width();
	  		lpl = lplb;
         lpmb = lpmbb;
  		}
   }
   else
   {
   	lpl = lplb = bits + (rdib->Height() - y) * rdib->Width() + lpAniGifPic->x;
      for(j=0;j<lpAniGifPic->height;j++)
		{
      	for(i=0;i<lpAniGifPic->width;i++)
         {
				*lpmb++ = *lpl++;	     		
         }
         lplb += rdib->Width();
			lpmbb += rdib->Width();
	  		lpl = lplb;
         lpmb = lpmbb;
      }
   }
}

void NoneFilter()
{
}